IAT : TABLE D'ADRESSES DES IMPORTATIONS
DE FONCTIONS



I - Structure de l'Import Address Table
II - Ajoutez vos propres DLL ou Fonctions manuellement.
III - Les IAT hors normes.
IV - Les différents liens.
V - Programme d'automatisation.



Cette table ne fait pas partie du PE Header. C'est une section à part entière souvent appelée .idata ou parfois .rdata. On peut même trouver les deux ensembles, mais je ne pourrais pas vous dire pourquoi, je ne suis pas allé aussi loin dans mes recherches.
Le rôle de cette section est vital. Pour faire simple, elle contient les noms des DLLs et de chacune de leurs fonctions utilisées par votre programme.
En pratique si votre programme utilise seulement ExitProcess (de Kernel32.dll) et MessageBoxA (User32.dll), ils sont tous inscrits dans cette section et vous ne pouvez utiliser aucune des autres fonctions de Kernel ou User32 parce que même si elles existent (et elles existent), elles ne sont pas notifiées dans ce carnet de bord. Vous pouvez encore moins utiliser des fonctions provenant d'autres DLLs.

Sachez une dernière chose, les fonctions importées, sont retrouvées soit d'après leur nom soit d'après un numéro. Celui-ci est appelé l'ORDINAL de la fonction.



Quel est l'intérêt ?

C'est qu'en comprenant sa construction on va pouvoir rajouter des fonctions dont nous ne pouvions pas nous servir jusque là, pour par exemple reverser une partie d'un programme. Mieux encore, on va pouvoir rajouter le nom d'une DLL et de ses fonctions, construite par nous même et ainsi vraiment développer ce qui nous tient à coeur.


SECTION .idata
1er DWORD Original First Thunk (c'est un RVA)
2nd DWORD Date Time Stamp (c'est un RVA)
3e DWORD Forwarder Chain FFFFFFFFh
4e DWORD Name (c'est un RVA)
5e DWORD First Thunk (c'est un RVA)
 IMAGE_IMPORT_DESCRIPTOR
1er DWORD Original First Thunk (c'est un RVA)
2nd DWORD Date Time Stamp (c'est un RVA)
3e DWORD Forwarder Chain FFFFFFFFh
4e DWORD Name (c'est un RVA)
5e DWORD First Thunk (c'est un RVA)
 IMAGE_IMPORT_DESCRIPTOR
........
.......   Il existe autant de structures IMAGE_IMPORT_DESCRIPTOR qu'il y a de DLL appellées par votre programme
....      + un dernier IMAGE_IMPORT_DESCRIPTOR remplit de 5 DWORD NULL en tant que terminaison
..

DWORD 1 (c'est un RVA (ou Ordinal))
DWORD 2 (c'est un RVA (ou Ordinal))
DWORD 3 (c'est un RVA (ou Ordinal))
DWORD ... (c'est un RVA (ou Ordinal))
DWORD n (c'est un RVA (ou Ordinal))
DWORD NULL 00000000h
IMAGE_THUNK_DATA Le vrai nom c'est bien IMAGE_THUNK_DATA mais par abus de langage je péfère appeler la totalités de ces groupes ORIGINAL_FIRST_THUNK parce que ce sont les membres OriginalFirstThunk qui pointent sur chacun d'eux. Idem pour FIRST_THUNK
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
NULL
DWORD 1 (c'est un RVA (ou Ordinal))
DWORD 2 (c'est un RVA (ou Ordinal))
DWORD 3 (c'est un RVA (ou Ordinal))
DWORD ... (c'est un RVA (ou Ordinal))
DWORD n (c'est un RVA (ou Ordinal))
DWORD NULL 00000000h
IMAGE_THUNK_DATA  
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
IMAGE_THUNK_DATA
NULL

........
...... Cette fois-ci, pour une DLL en particulier, il y aura autant de IMAGE_THUNK_DATA qu'elle a de fonctions
.....  exportées.
....   + un dernier DWORD mis à NULL pour notifier de la fin des données concernant cette DLL. IMAGE_THUNK_DATA
....   donne LES pointeurs vers des structures IMAGE_IMPORT_BY_NAME qui contienent le n°ORDINAL+NOM de la
....   fonction. (C'est pas tout à fait exact, on verra plus tard le cas des Fonctions importés par ORDINAL seul)

WORD n°Ordinal
TAILLE INDÉFINIE Nom de la fonction
IMAGE_IMPORT_BY_NAME
(Pour la 1ere fonction de la DLL 1)
WORD n°Ordinal
TAILLE INDÉFINIE Nom de la fonction
IMAGE_IMPORT_BY_NAME
(Pour la 2e fonction de la DLL 1)
WORD n°Ordinal
TAILLE INDÉFINIE Nom de la fonction
IMAGE_IMPORT_BY_NAME
(Pour la nième fonction de la DLL 1)

WORD n°Ordinal
TAILLE INDÉFINIE Nom de la fonction
IMAGE_IMPORT_BY_NAME
(Pour la 1ere fonction de la DLL 2)
WORD n°Ordinal
TAILLE INDÉFINIE Nom de la fonction
IMAGE_IMPORT_BY_NAME
(Pour la 2e fonction de la DLL 2)
WORD n°Ordinal
TAILLE INDÉFINIE Nom de la fonction
IMAGE_IMPORT_BY_NAME
(Pour la nième fonction de la DLL 2)

...
... Il y a autant de fois de Structures IMAGE_IMPORT_BY_NAME qu'il y a de Fonctions dans la DLL considérée.
... Donc ici on considère que notre programme n'importe que 3 fonctions appartenant à la DLL1 par exemple.
...

 

DISSECTION :

Dans la section .idata toutes les références pour aller d'une adresse à une autre sont définit par rapport au tout début du programme (MZ). C'est pour ça qu'elle n'utilise que des RVA pour décrire l'emplacement d'une autre adresse. Pour éclaircir ce point, un RVA c'est pas une adresse, c'est un déplacement par rapport à un point fixe. Un RVA c'est une distance tout simplement.

IMAGE_IMPORT_DESCRIPTOR:

Chaque structure IMAGE_IMPORT_DESCRIPTOR est destinée à une DLL. Et elle contient toujours 5 membres de taille DWORD. Le premier et dernier membre (Original First Thunk et First Thunk) pointent sur deux autres structures qui normalement sont identiques. Dans l'exemple ci-dessus je n'ai représenté qu'une seule fois ce tableau mais il y a son double qui le suit normalement et chacun des deux (Original First Thunk et First Thunk) pointe sur un tableau (jumeau)
Date Time Stamp, normalement, il est mis à 00000000h, sauf dans le cas où le programme présente une section "Delay Import Descriptor". Dans ce cas seulement ce dword représente la date complète de création de la DLL. Pour ce que j'en ai compris, "Delay Import Descriptor" serait un équivalent de l'IAT mis à par qu'on y trouverait les véritables adresses des fonctions de la DLL. Et c'est pour ça que sa date de conception devient importante, c'est pour trier les différentes versions d'une même DLL. (Vous remarquerez que "Delay Import Descriptor" n'est pas accessible dans ProcDump, et y en a un autre aussi)
Forwarder Chain est un dword réservé et d'après la doc officielle il doit être mis à FFFFFFFFh cependant, je l'ai déjà rencontré à 00000000h lui aussi.
Name est l'adresse (On parle toujours en adresse relative et c'est vrai pour tout le tut:RVA) où commence la chaîne de caractères représentant le nom de la DLL en question. Cette chaîne sera toujours suivit d'un byte 00h de terminaison. Dans l'exemple, je n'ai pas représenté ou était sa position, cette adresse se trouve à la suite de tous les tableaux, à la fin de la section .idata. Et d'ailleurs cette fin de tableau contient les noms de DLL+00 puis les noms DES Fonctions+00 et on recommence pour la DLL suivante. Cependant, on peut très bien prendre un ordre complètement différent.


IMAGE_THUNK_DATA :

Grâce à ce qui précède, on connait les noms des DLLs utilisées par notre programme. Reste à connaître chacune des fonctions de chaque DLL. C'est le rôle de IMAGE_THUNK_DATA. Chaque DWORD qu'elle contient représente l'adresse où on va retrouver le n°ORDINAL de la fonction + son nom qui le suit tout de suite après.
Un DWORD pointe donc sur : n°ORDINAL(de longueur 1 WORD)+Chaine de caractère(nom d'une fonction)+00h pour la terminaison.
Mais il y a un cas particulier. Ce DWORD n'est pas toujours une adresse vers ces deux données. Si le MSB (le byte de poids fort du DWORD est à 1) alors ça signifie qu'il ne faut pas le considérer comme un RVA. Et dans ce cas seuleument l'autre partie de ce DWORD (le WORD Bas) est le n°ORDINAL de la fonction. Dans cette configuration particulière on n'a pas de nom pour notre fonction. On sait seulement que notre programme l'utilise en se référent à son n°. (Il est possible de retrouver son nom mais alors il faut aller le chercher dans la table d'exportation de la DLL avec le même n° trouvé).

IMAGE_IMPORT_BY_NAME :

Il en existe autant qu'il y a de fonctions, forcément (excepté dans le cas des ordinaux), puisqu'elles contiennent le n° et noms de ces fonctions. La taille de cette structure est non définit puisqu'elle dépend toujours de la longeur des noms qu'elle contient.
Cependant vous trouverez une taille de 3 Bytes si vous lui faites subir un SIZEOF..... Car elle est ainsi définit dans la bibliothèque Windows.inc

IMAGE_IMPORT_BY_NAME STRUCT
   Hint dw ?                     ; <------------------------------n°ORDINAL
   Name1 db ?                 ; <------------------------------Nom de la fonction
IMAGE_IMPORT_BY_NAME ENDS


Mais comprenez que vous ne pouvez et ne devez sûrtout pas accepter cette valeur comme étant viable.




Par Morgatte